<?php
/**
 * Driver
 *
 * PDO链接数据库
 *
 * @author   songhuan <iphper@yeah.net>
 * @version   $Id: Driver.php 1 2010-08-10 14:40:00Z $
 */
class Driver
{
	/**
     * Database connection
     *
     * @var object|resource|null
     */
	protected $_connection  = null;

	/**
     * Specifies the case of column names retrieved in queries
     * Options
     * PDO::CASE_NATURAL (default)
     * PDO::CASE_LOWER
     * PDO::CASE_UPPER
     *
     * @var integer
     */
    protected $_caseFolding = PDO::CASE_NATURAL;

	/**
     * obtain the case setting, if there is one
     */
	public function setCaseFolding($case = PDO::CASE_NATURAL)
    {
    	switch ($case) 
		{
			case PDO::CASE_NATURAL:
			case PDO::CASE_LOWER:
			case PDO::CASE_UPPER:
				$this->caseFolding = $case;
				break;
			default:
				throw new Exception('Case must be one of the following constants: '
                        . 'Pdo::CASE_NATURAL, Pdo::CASE_LOWER, Pdo::CASE_UPPER');
				break;
		}
    }

	public function __destruct()
	{
		$this->closeConnection();
	}
	
	/**
     * 返回一个链接数据库资源
     * 如果$this->_connection 不是一个资源，初始化$this->_connection
     *
     * @return object|resource|null
     */
	public function getConnection()
    {
        $this->_connect();
        return $this->_connection;
    }

	/**
     * $this->_connection是否是一个可用资源
     *
     * @return bool
     */
	public function isConnected()
    {
        return ((boolean) ($this->_connection instanceof PDO));
    }

	/**
     * 清空资源
     * 
     * @return void
     */
    public function closeConnection()
    {
        $this->_connection = null;
    }

	/**
     * 链接数据库
     * 
     * @return void
     */
	private function _connect($config = null)
    {
    	if ($this->isConnected()) 
			return;
		
    	/*
		 * 没有开启pdo扩展
		 */
		if (!extension_loaded('pdo')) 
			throw new Exception('The PDO extension is required for this adapter but the extension is not loaded');
    	
   	 	if (!array_key_exists('db', V::$config)) 
			throw new Exception('The Config Db cannot empty');
		
		if (array_key_exists('caseFolding', V::$config['db']))
			$this->setCaseFolding(V::$config['db']['caseFolding']);

		try 
		{
			$this->_connection = new PDO(
				V::$config['db']['dsn'],
				V::$config['db']['username'],
				V::$config['db']['password']);

			if (array_key_exists('charset', V::$config['db'])) 
			{
				$driver = strtolower($this->_connection->getAttribute(PDO::ATTR_DRIVER_NAME));
				if (!in_array($driver, array('sqlite', 'mssql', 'dblib', 'sqlsrv')))
					$this->_connection->exec('SET NAMES '.V::$config['db']['charset']);
			}
			$this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding);
			$this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		} 
		catch (PDOException $e) 
		{
			throw new Exception('Can not connect database: ' . $e->getMessage());
		}
    }
    
	/**
     * 开启事务
     */
	public function beginTransaction()
    {
    	$this->getConnection();
    	$this->_connection->beginTransaction();
    }

	/**
     * 事务回滚
     * 
     * @return void
     */
    public function rollBack()
    {
    	$this->_connection->rollBack();
    }

	/**
     * 提交事务
     * 
     * @return void
     */
    public function commit()
    {
    	$this->_connection->commit();
    }

	/**
     * Transaction exec
     *
     * @param mixed array $sqls
     */
    public function execs(array $sqls = array())
    {
    	$this->beginTransaction();
    	foreach ($sqls as $sql)
    	{
    		try 
    		{
				$this->_connection->exec($sql);
			} 
			catch (PDOException $e) 
			{
				$this->rollBack();
            	throw new Exception($e->getMessage());
			}
    	}
    	$this->commit();
    }
    
	/**
     * 返回最后一次插入表的ID
     *
     * @return int
     */
	public function lastInsertId()
    {
    	try 
    	{
            return $this->_connection->lastInsertId();
    	}
		catch (PDOException $e)
		{ 
            throw new Exception($e->getMessage());
		}
    }
}
